package com.droid.lib.controls.widget.calendardialog;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;

import com.droid.lib.controls.util.MResource;

import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.format.DateUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
 * 日历选择器弹出框
 * @author Administrator
 *
 */
@SuppressLint("NewApi")
public class CalendarDatePickerDialog extends DialogFragment implements OnClickListener, CalendarDatePickerController {

	private static final String KEY_SELECTED_YEAR = "year";
	private static final String KEY_SELECTED_MONTH = "month";
	private static final String KEY_SELECTED_DAY = "day";
	private static final String KEY_LIST_POSITION = "list_position";
	private static final String KEY_WEEK_START = "week_start";
	private static final String KEY_YEAR_START = "year_start";
	private static final String KEY_YEAR_END = "year_end";

	private static final int DEFAULT_START_YEAR = 1900;
	private static final int DEFAULT_END_YEAR = 2100;

	private static final int ANIMATION_DURATION = 300;
	private static final int ANIMATION_DELAY = 500;

	private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("dd", Locale.getDefault());

	private final Calendar mCalendar = Calendar.getInstance();
	private OnDateSetListener mCallBack;
	private HashSet<OnDateChangedListener> mListeners = new HashSet<>();

	private AccessibleDateAnimator mAnimator;

	private TextView mDayOfWeekView;
	private LinearLayout mMonthAndDayView;
	private TextView mSelectedMonthTextView;
	private TextView mSelectedDayTextView;
	private DayPickerView mDayPickerView;

	private int mWeekStart = mCalendar.getFirstDayOfWeek();
	private int mMinYear = DEFAULT_START_YEAR;
	private int mMaxYear = DEFAULT_END_YEAR;

	private boolean mDelayAnimation = true;

	private String mDayPickerDescription;
	private String mSelectDay;
	private static Context mContext;

	public interface OnDateSetListener {
		void onDateSet(CalendarDatePickerDialog dialog, int year, int monthOfYear, int dayOfMonth);
	}

	public interface OnDateChangedListener {
		void onDateChanged();
	}

	public CalendarDatePickerDialog() {

	}

	public static CalendarDatePickerDialog newInstance(Context context, OnDateSetListener callBack, int year,
			int monthOfYear, int dayOfMonth) {
		CalendarDatePickerDialog ret = new CalendarDatePickerDialog();
		mContext = context;
		ret.initialize(callBack, year, monthOfYear, dayOfMonth);
		return ret;
	}

	public void initialize(OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
		mCallBack = callBack;
		mCalendar.set(Calendar.YEAR, year);
		mCalendar.set(Calendar.MONTH, monthOfYear);
		mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		final Activity activity = getActivity();
		activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
		if (savedInstanceState != null) {
			mCalendar.set(Calendar.YEAR, savedInstanceState.getInt(KEY_SELECTED_YEAR));
			mCalendar.set(Calendar.MONTH, savedInstanceState.getInt(KEY_SELECTED_MONTH));
			mCalendar.set(Calendar.DAY_OF_MONTH, savedInstanceState.getInt(KEY_SELECTED_DAY));
		}
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putInt(KEY_SELECTED_YEAR, mCalendar.get(Calendar.YEAR));
		outState.putInt(KEY_SELECTED_MONTH, mCalendar.get(Calendar.MONTH));
		outState.putInt(KEY_SELECTED_DAY, mCalendar.get(Calendar.DAY_OF_MONTH));
		outState.putInt(KEY_WEEK_START, mWeekStart);
		outState.putInt(KEY_YEAR_START, mMinYear);
		outState.putInt(KEY_YEAR_END, mMaxYear);
		int listPosition = mDayPickerView.getMostVisiblePosition();

		outState.putInt(KEY_LIST_POSITION, listPosition);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
		LinearLayout layout = new LinearLayout(mContext);
		LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MResource.getDip(mContext, 270),
				LinearLayout.LayoutParams.MATCH_PARENT);

		layout.setLayoutParams(layoutParams);
		layout.setGravity(Gravity.CENTER);
		layout.setBackgroundColor(Color.parseColor("#f2f2f2"));
		layout.setOrientation(LinearLayout.VERTICAL);
		LinearLayout.LayoutParams calendarDatePickerSelectedDateParams = new LinearLayout.LayoutParams(
				MResource.getDip(mContext, 270), 0, 1);

		LinearLayout calendarDatePickerSelectedDateLayout = new LinearLayout(mContext);
		calendarDatePickerSelectedDateLayout.setLayoutParams(calendarDatePickerSelectedDateParams);
		calendarDatePickerSelectedDateLayout.setBackgroundColor(Color.WHITE);
		calendarDatePickerSelectedDateLayout.setGravity(Gravity.CENTER);
		calendarDatePickerSelectedDateLayout.setClickable(true);
		calendarDatePickerSelectedDateLayout.setOrientation(LinearLayout.VERTICAL);
		layout.addView(calendarDatePickerSelectedDateLayout);
		mMonthAndDayView = new AccessibleLinearLayout(mContext);
		LinearLayout.LayoutParams accessibleLinearLayoutParams = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.MATCH_PARENT, 0, 1);
		mMonthAndDayView.setLayoutParams(accessibleLinearLayoutParams);
		mMonthAndDayView.setGravity(Gravity.CENTER);
		mMonthAndDayView.setClickable(true);
		mMonthAndDayView.setOrientation(LinearLayout.VERTICAL);
		mMonthAndDayView.setLayoutParams(accessibleLinearLayoutParams);
		mMonthAndDayView.setBackgroundColor(Color.WHITE);
		layout.addView(mMonthAndDayView);
		// 月份
		mSelectedMonthTextView = new TextView(mContext);
		LinearLayout.LayoutParams datePickerMonthParams = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
		datePickerMonthParams.setMargins(0, 10, 0, 0);
		mSelectedMonthTextView.setLayoutParams(datePickerMonthParams);
		mSelectedMonthTextView.setDuplicateParentStateEnabled(true);
		mSelectedMonthTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
		mSelectedMonthTextView.setIncludeFontPadding(false);
		int[] state1 = { android.R.attr.state_pressed };
		int[] state2 = { -android.R.attr.state_pressed, android.R.attr.state_selected };
		int[] state3 = { -android.R.attr.state_pressed, -android.R.attr.state_selected };
		int[][] states = { state1, state2, state3 };
		int[] colors = { Color.parseColor("#0099cc"), Color.parseColor("#33b5e5"), Color.parseColor("#ff999999") };
		ColorStateList colorStateList = new ColorStateList(states, colors);
		mSelectedMonthTextView.setTextColor(colorStateList);
		mSelectedMonthTextView.setTextSize(20);
		mMonthAndDayView.addView(mSelectedMonthTextView);

		// 日
		mSelectedDayTextView = new TextView(mContext);
		LinearLayout.LayoutParams datePickerDayParams = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
		datePickerDayParams.setMargins(0, -10, 0, -10);
		mSelectedDayTextView.setLayoutParams(datePickerDayParams);
		mSelectedDayTextView.setDuplicateParentStateEnabled(true);
		mSelectedDayTextView.setGravity(Gravity.CENTER);
		mSelectedDayTextView.setIncludeFontPadding(false);
		mSelectedDayTextView.setTextColor(colorStateList);
		mSelectedDayTextView.setTextSize(50);
		mMonthAndDayView.addView(mSelectedDayTextView);
		// 日历控件
		mAnimator = new AccessibleDateAnimator(mContext);
		LinearLayout.LayoutParams animatorDateParams = new LinearLayout.LayoutParams(MResource.getDip(mContext, 270),
				MResource.getDip(mContext, 270));
		mAnimator.setLayoutParams(animatorDateParams);
		mAnimator.setForegroundGravity(Gravity.CENTER);
		mAnimator.setBackgroundColor(Color.parseColor("#f2f2f2"));
		layout.addView(mAnimator);
		LinearLayout.LayoutParams viewlineDateParams = new LinearLayout.LayoutParams(MResource.getDip(mContext, 270),
				MResource.getDip(mContext, 1));
		View viewline = new View(mContext);
		viewline.setLayoutParams(viewlineDateParams);
		viewline.setBackgroundColor(Color.parseColor("#cccccc"));
		layout.addView(viewline);
		LinearLayout bottonLinearLayout = new LinearLayout(mContext);
		bottonLinearLayout.setScrollBarStyle(android.R.attr.buttonBarButtonStyle);
		LinearLayout.LayoutParams bottonLinearLayoutParams = new LinearLayout.LayoutParams(
				MResource.getDip(mContext, 270), LinearLayout.LayoutParams.WRAP_CONTENT);
		bottonLinearLayout.setLayoutParams(bottonLinearLayoutParams);
		bottonLinearLayout.setOrientation(LinearLayout.VERTICAL);
		layout.addView(bottonLinearLayout);
		Button done = new Button(mContext);
		LinearLayout.LayoutParams doneParams = new LinearLayout.LayoutParams(MResource.getDip(mContext, 270),
				LinearLayout.LayoutParams.WRAP_CONTENT, 1);
		done.setLayoutParams(doneParams);
		done.setMinHeight(MResource.getDip(mContext, 48));
		done.setText("确定");
		done.setTextSize(20);
		done.setTextColor(Color.parseColor("#8c8c8c"));
		bottonLinearLayout.addView(done);
		// mDayOfWeekView = (TextView)
		// view.findViewById(R.id.date_picker_header);
		mMonthAndDayView.setOnClickListener(this);

		int listPosition = -1;

		if (savedInstanceState != null) {
			mWeekStart = savedInstanceState.getInt(KEY_WEEK_START);
			mMinYear = savedInstanceState.getInt(KEY_YEAR_START);
			mMaxYear = savedInstanceState.getInt(KEY_YEAR_END);
			listPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
		}

		mDayPickerView = new SimpleDayPickerView(mContext, this);
		mDayPickerDescription = "Month grid of days";
		mSelectDay = "Select month and day";
		mAnimator.addView(mDayPickerView);
		mAnimator.setDateMillis(mCalendar.getTimeInMillis());

		Animation animation = new AlphaAnimation(0.0f, 1.0f);
		animation.setDuration(ANIMATION_DURATION);
		mAnimator.setInAnimation(animation);

		Animation animation2 = new AlphaAnimation(1.0f, 0.0f);
		animation2.setDuration(ANIMATION_DURATION);
		mAnimator.setOutAnimation(animation2);

		done.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mCallBack != null) {
					mCallBack.onDateSet(CalendarDatePickerDialog.this, mCalendar.get(Calendar.YEAR),
							mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
				}
				dismiss();
			}
		});

		updateDisplay(false);
		setCurrentView();

		if (listPosition != -1) {
			mDayPickerView.postSetSelection(listPosition);
		}

		return layout;
	}

	private void setCurrentView() {
		long millis = mCalendar.getTimeInMillis();

		ObjectAnimator pulseAnimator = Utils.getPulseAnimator(mMonthAndDayView, 0.9f, 1.05f);
		if (mDelayAnimation) {
			pulseAnimator.setStartDelay(ANIMATION_DELAY);
			mDelayAnimation = false;
		}
		mDayPickerView.onDateChanged();
		mMonthAndDayView.setSelected(true);

		pulseAnimator.start();

		int flags = DateUtils.FORMAT_SHOW_DATE;
		String dayString = DateUtils.formatDateTime(getActivity(), millis, flags);
		mAnimator.setContentDescription(mDayPickerDescription + ": " + dayString);
		Utils.tryAccessibilityAnnounce(mAnimator, mSelectDay);
	}

	private void updateDisplay(boolean announce) {
		if (mDayOfWeekView != null) {
			mDayOfWeekView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault())
					.toUpperCase(Locale.getDefault()));
		}

		mSelectedMonthTextView.setText(mCalendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())
				.toUpperCase(Locale.getDefault()));
		mSelectedDayTextView.setText(DAY_FORMAT.format(mCalendar.getTime()));

		long millis = mCalendar.getTimeInMillis();
		mAnimator.setDateMillis(millis);
		int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR;
		String monthAndDayText = DateUtils.formatDateTime(getActivity(), millis, flags);
		mMonthAndDayView.setContentDescription(monthAndDayText);

		if (announce) {
			flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
			String fullDateText = DateUtils.formatDateTime(getActivity(), millis, flags);
			Utils.tryAccessibilityAnnounce(mAnimator, fullDateText);
		}
	}

	public void setFirstDayOfWeek(int startOfWeek) {
		if (startOfWeek < Calendar.SUNDAY || startOfWeek > Calendar.SATURDAY) {
			throw new IllegalArgumentException("Value must be between Calendar.SUNDAY and " + "Calendar.SATURDAY");
		}
		mWeekStart = startOfWeek;
		if (mDayPickerView != null) {
			mDayPickerView.onChange();
		}
	}

	public void setYearRange(int startYear, int endYear) {
		if (endYear <= startYear) {
			throw new IllegalArgumentException("Year end must be larger than year start");
		}
		mMinYear = startYear;
		mMaxYear = endYear;
		if (mDayPickerView != null) {
			mDayPickerView.onChange();
		}
	}

	public void setOnDateSetListener(OnDateSetListener listener) {
		mCallBack = listener;
	}

	private void adjustDayInMonthIfNeeded(int month, int year) {
		int day = mCalendar.get(Calendar.DAY_OF_MONTH);
		int daysInMonth = Utils.getDaysInMonth(month, year);
		if (day > daysInMonth) {
			mCalendar.set(Calendar.DAY_OF_MONTH, daysInMonth);
		}
	}

	@Override
	public void onClick(View v) {
		if (v.equals(mMonthAndDayView)) {
			setCurrentView();
		}
	}

	@Override
	public void onYearSelected(int year) {
		adjustDayInMonthIfNeeded(mCalendar.get(Calendar.MONTH), year);
		mCalendar.set(Calendar.YEAR, year);
		updatePickers();
		setCurrentView();
		updateDisplay(true);
	}

	@Override
	public void onDayOfMonthSelected(int year, int month, int day) {
		mCalendar.set(Calendar.YEAR, year);
		mCalendar.set(Calendar.MONTH, month);
		mCalendar.set(Calendar.DAY_OF_MONTH, day);
		updatePickers();
		updateDisplay(true);
	}

	private void updatePickers() {
		for (OnDateChangedListener mListener : mListeners) {
			mListener.onDateChanged();
		}
	}

	@Override
	public MonthAdapter.CalendarDay getSelectedDay() {
		return new MonthAdapter.CalendarDay(mCalendar);
	}

	@Override
	public int getMinYear() {
		return mMinYear;
	}

	@Override
	public int getMaxYear() {
		return mMaxYear;
	}

	@Override
	public int getFirstDayOfWeek() {
		return mWeekStart;
	}

	@Override
	public void registerOnDateChangedListener(OnDateChangedListener listener) {
		mListeners.add(listener);
	}

	@Override
	public void unregisterOnDateChangedListener(OnDateChangedListener listener) {
		mListeners.remove(listener);
	}
}
